{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "1424a3fd",
   "metadata": {},
   "source": [
    "# [ Chapter 9 - Personalized Search ]\n",
    "# Personalized Search"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a2ad52b6",
   "metadata": {},
   "source": [
    "**NOTE**: This notebook depends upon the the Retrotech dataset. If you have any issues, please rerun the [Setting up the Retrotech Dataset](../ch04/1.setting-up-the-retrotech-dataset.ipynb) notebook or execute the next cell uncommented."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "f83e1a49",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import random\n",
    "from datetime import datetime\n",
    "\n",
    "from pyspark.conf import SparkConf\n",
    "from pyspark.ml.feature import IndexToString, StringIndexer\n",
    "from pyspark.sql import SparkSession\n",
    "from pyspark.sql.functions import col, explode\n",
    "\n",
    "from aips import display_product_search, get_engine\n",
    "from aips.spark import create_view_from_collection\n",
    "from aips.spark.dataframe import from_sql\n",
    "\n",
    "engine = get_engine()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "65b1073e",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "#Recommended for making ALS run faster, if you have enough memory / cores allocated to docker\n",
    "conf = SparkConf()\n",
    "conf.set(\"spark.driver.memory\", \"8g\")\n",
    "conf.set(\"spark.executor.memory\", \"8g\")\n",
    "conf.set(\"spark.dynamicAllocation.enabled\", \"true\")\n",
    "conf.set(\"spark.dynamicAllocation.executorMemoryOverhead\", \"8g\")\n",
    "spark = SparkSession.builder.appName(\"AIPS-ch9\").config(conf=conf).getOrCreate()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "3c376197",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "#%run chapters/ch04/1.setting-up-the-retrotech-dataset.ipynb"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "48197bec",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "### Load product data\n",
    "products_collection = engine.get_collection(\"products\")\n",
    "create_view_from_collection(products_collection, \"products\", spark)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4d1f3344",
   "metadata": {},
   "source": [
    "# Collaborative Filtering with Implicit Preferences"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "845c2f03",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def aggregate_signals(signals_collection, signals_agg_collection_name, query):\n",
    "    aggregated_collection = engine.create_collection(signals_agg_collection_name)\n",
    "    print(\"Aggregating Signals to Create Signals Boosts...\")\n",
    "    create_view_from_collection(signals_collection, \"signals\", spark)\n",
    "    aggregated_collection.write(from_sql(query, spark))\n",
    "    print(\"Signals Aggregation Completed!\")\n",
    "    return aggregated_collection"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fbbbcdb4",
   "metadata": {},
   "source": [
    "## Listing 9.1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "721bec00",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wiping \"user_product_implicit_preferences\" collection\n",
      "Creating \"user_product_implicit_preferences\" collection\n",
      "Aggregating Signals to Create Signals Boosts...\n",
      "Successfully written 647441 documents\n",
      "Signals Aggregation Completed!\n"
     ]
    }
   ],
   "source": [
    "click_weight = 1\n",
    "add_to_cart_weight = 0 ##increase to consider add-to-cart signals\n",
    "purchase_weight = 0 ##increase to consider purchase signals\n",
    "\n",
    "signals_collection = engine.get_collection(\"signals\")\n",
    "\n",
    "mixed_signal_types_aggregation = f\"\"\"\n",
    "SELECT user, product,\n",
    "  (click_boost + add_to_cart_boost + purchase_boost) AS rating\n",
    "FROM (\n",
    "  SELECT user, product, \n",
    "    SUM(click) AS click_boost,\n",
    "    SUM(add_to_cart) AS add_to_cart_boost,\n",
    "    SUM(purchase) AS purchase_boost\n",
    "  FROM (  \n",
    "    SELECT s.user, s.target AS product, \n",
    "      IF(s.type = 'click', {click_weight}, 0) AS click, \n",
    "      IF(s.type = 'add-to-cart', {add_to_cart_weight}, 0) AS add_to_cart,\n",
    "      IF(s.type = 'purchase', {purchase_weight}, 0) AS purchase\n",
    "    FROM signals s \n",
    "    WHERE (s.type != 'query')) AS raw_signals\n",
    "  GROUP BY user, product) AS per_type_boosts\"\"\"\n",
    "\n",
    "signals_agg_collection = \\\n",
    "  aggregate_signals(signals_collection, \"user_product_implicit_preferences\",\n",
    "                    mixed_signal_types_aggregation)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a5d89193",
   "metadata": {},
   "source": [
    "## Listing 9.2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "c4d19491",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "create_view_from_collection(signals_agg_collection, \"user_product_implicit_preferences\", spark)\n",
    "\n",
    "##50K = all products\n",
    "#This will take long time. Recommend setting to 1,000 if trying to just run through code\n",
    "#without considering all products\n",
    "\n",
    "top_product_count_for_recs = 50000 #1000 for older computers \n",
    "user_preference_query = f\"\"\"\n",
    "SELECT user, product, rating\n",
    "FROM user_product_implicit_preferences\n",
    "WHERE product IN (\n",
    "  SELECT product FROM (\n",
    "    SELECT product, COUNT(user) user_count\n",
    "    FROM user_product_implicit_preferences\n",
    "    GROUP BY product\n",
    "    ORDER BY user_count DESC\n",
    "    LIMIT {top_product_count_for_recs}\n",
    "  ) AS top_products)   \n",
    "ORDER BY rating DESC\"\"\"\n",
    "\n",
    "user_prefs = spark.sql(user_preference_query)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "38e9335d",
   "metadata": {},
   "source": [
    "## Listing 9.3 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "4920cdad",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "+-------+------------+------+---------+------------+\n",
      "|   user|     product|rating|userIndex|productIndex|\n",
      "+-------+------------+------+---------+------------+\n",
      "|u159789|008888345435|     1|      0.0|      5073.0|\n",
      "|u159789|014633196870|     1|      0.0|      4525.0|\n",
      "|u159789|018713571687|     1|      0.0|     10355.0|\n",
      "|u159789|024543718710|     1|      0.0|       263.0|\n",
      "|u159789|025192979620|     1|      0.0|     12289.0|\n",
      "|u159789|025193102324|     1|      0.0|      9650.0|\n",
      "|u159789|085391163121|     1|      0.0|      9196.0|\n",
      "|u159789|720616236029|     1|      0.0|      2781.0|\n",
      "|u159789|801213001996|     1|      0.0|     28736.0|\n",
      "|u159789|813985010007|     1|      0.0|      5819.0|\n",
      "+-------+------------+------+---------+------------+\n",
      "only showing top 10 rows\n",
      "\n"
     ]
    }
   ],
   "source": [
    "#Sometimes fails on first execution\n",
    "#Fits a model to the input dataset with optional parameters.\n",
    "def order_preferences(prefs):\n",
    "    return prefs.orderBy(col(\"userIndex\").asc(),\n",
    "                         col(\"rating\").desc(),\n",
    "                         col(\"product\").asc())\n",
    "\n",
    "def strings_to_indexes(ratings, user_indexer,\n",
    "                       product_indexer):\n",
    "    transformed = product_indexer.transform(user_indexer.transform(ratings))\n",
    "    return order_preferences(transformed)\n",
    "\n",
    "def indexes_to_strings(ratings, user_indexer,\n",
    "                       product_indexer):\n",
    "    user_converter = IndexToString(inputCol=\"userIndex\",\n",
    "                                       outputCol=\"user\",\n",
    "                             labels=user_indexer.labels)\n",
    "    product_converter = IndexToString(inputCol=\"productIndex\",\n",
    "                                          outputCol=\"product\",\n",
    "                                labels=product_indexer.labels)\n",
    "    converted = user_converter.transform(\n",
    "        product_converter.transform(ratings))\n",
    "    return order_preferences(converted)\n",
    "\n",
    "user_indexer = StringIndexer(inputCol=\"user\", \n",
    "       outputCol=\"userIndex\").fit(user_prefs)\n",
    "product_indexer = StringIndexer(inputCol=\"product\",\n",
    "                          outputCol=\"productIndex\").fit(user_prefs)\n",
    "\n",
    "indexed_prefs = strings_to_indexes(user_prefs, user_indexer, product_indexer)\n",
    "indexed_prefs.show(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "30470626",
   "metadata": {},
   "source": [
    "## Listing 9.4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "b6b6a2fa",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Beginning model training\n",
      "Beginning predictions\n",
      "Beginning evaluation\n",
      "Root-mean-square error = 1.0007877733299877\n"
     ]
    }
   ],
   "source": [
    "from pyspark.ml.evaluation import RegressionEvaluator\n",
    "from pyspark.ml.recommendation import ALS\n",
    "from pyspark.sql import Row\n",
    "\n",
    "random.seed(0)\n",
    "\n",
    "als = ALS(maxIter=3, rank=10, regParam=0.15, implicitPrefs=True,\n",
    "          userCol=\"userIndex\", itemCol=\"productIndex\", ratingCol=\"rating\",\n",
    "          coldStartStrategy=\"drop\", seed=0)\n",
    "\n",
    "(training_data, test_data) = user_prefs.randomSplit([0.95, 0.05], 0)\n",
    "training_data = strings_to_indexes(training_data, user_indexer, product_indexer)\n",
    "test_data = strings_to_indexes(test_data, user_indexer, product_indexer)\n",
    "\n",
    "print(\"Beginning model training\")\n",
    "model = als.fit(training_data)\n",
    "\n",
    "print(\"Beginning predictions\")\n",
    "predictions = model.transform(test_data)\n",
    "\n",
    "print(\"Beginning evaluation\")\n",
    "evaluator = RegressionEvaluator(metricName=\"rmse\", labelCol=\"rating\",\n",
    "                                predictionCol=\"prediction\")\n",
    "rmse = evaluator.evaluate(predictions)\n",
    "print(f\"Root-mean-square error = {rmse}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0d4577f3",
   "metadata": {},
   "source": [
    "## Listing 9.5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "561d70cc",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "+---------+----------------------------------------------------------------+\n",
      "|userIndex|                                                 recommendations|\n",
      "+---------+----------------------------------------------------------------+\n",
      "|        0|[{6, 0.022541389}, {13, 0.015104328}, {36, 0.010634022}, {20,...|\n",
      "|        1|[{13, 0.009001873}, {3, 0.007981183}, {23, 0.0050935573}, {31...|\n",
      "|        2|[{9, 0.06319133}, {17, 0.04681776}, {3, 0.041046627}, {14, 0....|\n",
      "|        3|[{17, 0.0145240165}, {14, 0.01413305}, {12, 0.012459144}, {39...|\n",
      "|        4|[{14, 0.006752351}, {4, 0.004651022}, {10, 0.004487163}, {17,...|\n",
      "+---------+----------------------------------------------------------------+\n",
      "only showing top 5 rows\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# Generate top 10 product recommendations for each user\n",
    "indexed_user_recs = model.recommendForAllUsers(10) \\\n",
    "                         .orderBy(col(\"userIndex\").asc())\n",
    "indexed_user_recs.show(5, truncate=64)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8927aa9d",
   "metadata": {},
   "source": [
    "## Listing 9.6"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "67f5db2c",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "column_exploder = explode(\"recommendations\").alias(\"productIndex_rating\")\n",
    "user_item_recs = indexed_user_recs.select(\"userIndex\", column_exploder) \\\n",
    "                      .select(\"userIndex\", col(\"productIndex_rating.*\"))\n",
    "user_item_recs = indexes_to_strings(user_item_recs, user_indexer,\n",
    "                                    product_indexer)\n",
    "user_item_recs = user_item_recs.select(\"user\", \"product\",\n",
    "                                       col(\"rating\").alias(\"boost\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5d36d7d9",
   "metadata": {},
   "source": [
    "# Listing 9.7"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "4f26bb58",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Start Time: 2024-11-18 19:33:11\n",
      "Wiping \"user_item_recommendations\" collection\n",
      "Creating \"user_item_recommendations\" collection\n",
      "Successfully written 5212070 documents\n",
      "End Time: 2024-11-18 19:35:46\n"
     ]
    }
   ],
   "source": [
    "print(\"Start Time: \" + datetime.now().strftime(\"%Y-%m-%d %H:%M:%S\"))\n",
    "\n",
    "recs_collection = engine.create_collection(\"user_item_recommendations\")\n",
    "recs_collection.write(user_item_recs)\n",
    "\n",
    "print(\"End Time: \" + datetime.now().strftime(\"%Y-%m-%d %H:%M:%S\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aba10513",
   "metadata": {},
   "source": [
    "# Search with Recommendations Boosts\n",
    "Whereas signals boosting boosts the most popular documents for a particular query (ch8), you can also boost the most personalized items for a particular user. In order to serve up the pre-generated collaborative recommendations we just generated, we can just need to run a search and boost the recommended items for each user."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8dbb5db5",
   "metadata": {},
   "source": [
    "## Listing 9.8"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "40a1fda0",
   "metadata": {},
   "outputs": [],
   "source": [
    "from pyspark.sql.functions import date_format, lit\n",
    "from pyspark.sql.types import StructType, StructField, StringType, DateType\n",
    "\n",
    "def scrub(name): \n",
    "    return name.replace(\"&#xAE;\",\"®\").replace(\"&#x2122;\", \"™\")\n",
    "\n",
    "def print_interaction_history(user_id, signals):\n",
    "    products_collection = engine.get_collection(\"products\")    \n",
    "    interacted_products = [s[\"target\"] for s in signals]\n",
    "    request = {\"filters\": [(\"upc\", interacted_products)]}\n",
    "    products = products_collection.search(**request)[\"docs\"]    \n",
    "    product_info = {p[\"upc\"]: p[\"name\"] for p in products}\n",
    "    \n",
    "    is_epoch_format = isinstance(signals[0][\"signal_time\"], int)\n",
    "    for s in signals:        \n",
    "        if is_epoch_format:\n",
    "            s[\"signal_time\"] = datetime.now()\n",
    "        s |= {\"name\": scrub(product_info.get(s[\"target\"], s[\"target\"]))}\n",
    "\n",
    "    schema = StructType([StructField(\"signal_time\", DateType(), True),\n",
    "                         StructField(\"type\", StringType(), True),\n",
    "                         StructField(\"target\", StringType(), True),\n",
    "                         StructField(\"name\", StringType(), True)])\n",
    "    dataframe = spark.createDataFrame(signals, schema)\n",
    "    dataframe = dataframe.select(date_format('signal_time', 'MM/dd HH:MM').alias(\"signal_time\"),\n",
    "                                 \"type\", \"target\", \"name\")\n",
    "    \n",
    "    print(f\"Previous Product Interactions for User: {user_id}\")\n",
    "    dataframe.show(10, truncate=37)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "6d466229",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Previous Product Interactions for User: u478462\n",
      "+-----------+-----------+------------+-------------------------------------+\n",
      "|signal_time|       type|      target|                                 name|\n",
      "+-----------+-----------+------------+-------------------------------------+\n",
      "|11/18 00:11|      query|       apple|                                apple|\n",
      "|11/18 00:11|      click|885909457588|Apple® - iPad® 2 with Wi-Fi - 16GB...|\n",
      "|11/18 00:11|add-to-cart|885909457588|Apple® - iPad® 2 with Wi-Fi - 16GB...|\n",
      "|11/18 00:11|   purchase|885909457588|Apple® - iPad® 2 with Wi-Fi - 16GB...|\n",
      "|11/18 00:11|      query|     macbook|                              macbook|\n",
      "|11/18 00:11|      click|885909464043|Apple® - MacBook® Air - Intel® Cor...|\n",
      "+-----------+-----------+------------+-------------------------------------+\n",
      "\n"
     ]
    }
   ],
   "source": [
    "def signals_request(user_id):\n",
    "    return {\"query\": \"*\",\n",
    "            \"return_fields\": [\"signal_time\", \"type\", \"target\"],\n",
    "            \"order_by\": [(\"signal_time\", \"asc\")],\n",
    "            \"filters\": [(\"user\", user_id)]}\n",
    "\n",
    "user_id = \"u478462\" #example user\n",
    "signals_collection = engine.get_collection(\"signals\")\n",
    "\n",
    "request = signals_request(user_id)\n",
    "previous_signals = signals_collection.search(**request)[\"docs\"]\n",
    "print_interaction_history(user_id, previous_signals)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e2473c9f",
   "metadata": {},
   "source": [
    "## Listing 9.9"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "1d714963",
   "metadata": {},
   "outputs": [],
   "source": [
    "# %load -s product_search_request engine/search_requests\n",
    "def product_search_request(query, param_overrides={}):\n",
    "    request = {\"query\": query,\n",
    "               \"query_fields\": [\"name\", \"manufacturer\", \"long_description\"],\n",
    "               \"return_fields\": [\"upc\", \"name\", \"manufacturer\",\n",
    "                                 \"short_description\", \"score\"],\n",
    "               \"limit\": 5,\n",
    "               \"order_by\": [(\"score\", \"desc\"), (\"upc\", \"asc\")]}\n",
    "    return request | param_overrides"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "eb59c420",
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_query_time_boosts(user, boosts_collection):\n",
    "    request = {\"query\": \"*\",\n",
    "               \"return_fields\": [\"product\", \"boost\"],\n",
    "               \"filters\": [(\"user\", user)] if user else [],\n",
    "               \"limit\": 10,\n",
    "               \"order_by\": [(\"boost\", \"desc\")]}\n",
    "    \n",
    "    response = boosts_collection.search(**request)\n",
    "    signals_boosts = response[\"docs\"]\n",
    "    return \" \".join(f'\"{b[\"product\"]}\"^{b[\"boost\"] * 100}'\n",
    "                    for b in signals_boosts)\n",
    "\n",
    "def search_for_products(query, signals_boosts):\n",
    "    request = product_search_request(query if query else \"*\")\n",
    "    if signals_boosts:\n",
    "        request[\"query_boosts\"] = (\"upc\", signals_boosts)\n",
    "    return products_collection.search(**request)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "8a28fe58",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Boost Query:\n",
      "\"885909457588\"^83.317953 \"022265004289\"^19.800967 \"024543742180\"^8.756707 \"635753493559\"^6.914275 \"045496880484\"^6.1463382 \"635753493573\"^5.834811 \"885909457595\"^5.7118796 \"885370315080\"^5.6894064 \"612572171585\"^5.5108927 \"885909395095\"^5.2595586\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div id=\"demo\">\n",
       "\t<center><input style=\"width:40%\" readonly type=\"text\" name=\"q\" value=\"\">\n",
       "\t<input readonly type=\"submit\" value=\"Search\">\n",
       "\t</center>\n",
       "    <div class=\"results\">\n",
       "    \t\n",
       "\n",
       "    </div>\n",
       "</div>\n",
       "    \t<div style=\"position: relative; width: 100%; height:auto; overflow: auto;\">\n",
       "\t    \t<div style=\"position: relative; float:left; width: 120px; margin-top:5px\">\n",
       "\t    \t\t<img style=\"width:250px; height: auto; max-height:150px\" src=\"../../data/retrotech/images/885909457588.jpg\">\n",
       "\t    \t</div>\n",
       "\t    \t<div style=\"position:relative; float:left; clear:none; width: 80%; height:auto\">\n",
       "\t    \t\t<p style=\"font-size:24px; padding-left: 50px;\"><strong>\t\tName:</strong> Apple&#xAE; - iPad&#xAE; 2 with Wi-Fi - 16GB - Black\n",
       "\t\t\t\t\t<br><strong>\t\tManufacturer:</strong> Apple&#xAE;</p>\n",
       "\t    \t\t</p>\n",
       "\t    \t</div>\n",
       "    \t</div>\n",
       "    \t\n",
       "\t\t<div style=\"position:relative; clear:both; content: ' '; display: block; height: 1px; margin-top: 10px; margin-bottom:20px\">\n",
       "\t\t\t<hr style=\"color: gray; width: 95%;\" />\n",
       "\t\t</div>\n",
       "\t\t\n",
       "    \t<div style=\"position: relative; width: 100%; height:auto; overflow: auto;\">\n",
       "\t    \t<div style=\"position: relative; float:left; width: 120px; margin-top:5px\">\n",
       "\t    \t\t<img style=\"width:250px; height: auto; max-height:150px\" src=\"../../data/retrotech/images/635753493559.jpg\">\n",
       "\t    \t</div>\n",
       "\t    \t<div style=\"position:relative; float:left; clear:none; width: 80%; height:auto\">\n",
       "\t    \t\t<p style=\"font-size:24px; padding-left: 50px;\"><strong>\t\tName:</strong> Samsung - Galaxy Tab 10.1 - 16GB - Metallic Gray\n",
       "\t\t\t\t\t<br><strong>\t\tManufacturer:</strong> Samsung</p>\n",
       "\t    \t\t</p>\n",
       "\t    \t</div>\n",
       "    \t</div>\n",
       "    \t\n",
       "\t\t<div style=\"position:relative; clear:both; content: ' '; display: block; height: 1px; margin-top: 10px; margin-bottom:20px\">\n",
       "\t\t\t<hr style=\"color: gray; width: 95%;\" />\n",
       "\t\t</div>\n",
       "\t\t\n",
       "    \t<div style=\"position: relative; width: 100%; height:auto; overflow: auto;\">\n",
       "\t    \t<div style=\"position: relative; float:left; width: 120px; margin-top:5px\">\n",
       "\t    \t\t<img style=\"width:250px; height: auto; max-height:150px\" src=\"../../data/retrotech/images/635753493573.jpg\">\n",
       "\t    \t</div>\n",
       "\t    \t<div style=\"position:relative; float:left; clear:none; width: 80%; height:auto\">\n",
       "\t    \t\t<p style=\"font-size:24px; padding-left: 50px;\"><strong>\t\tName:</strong> Samsung - Galaxy Tab 10.1  - 32GB - Metallic Gray\n",
       "\t\t\t\t\t<br><strong>\t\tManufacturer:</strong> Samsung</p>\n",
       "\t    \t\t</p>\n",
       "\t    \t</div>\n",
       "    \t</div>\n",
       "    \t\n",
       "\t\t<div style=\"position:relative; clear:both; content: ' '; display: block; height: 1px; margin-top: 10px; margin-bottom:20px\">\n",
       "\t\t\t<hr style=\"color: gray; width: 95%;\" />\n",
       "\t\t</div>\n",
       "\t\t\n",
       "    \t<div style=\"position: relative; width: 100%; height:auto; overflow: auto;\">\n",
       "\t    \t<div style=\"position: relative; float:left; width: 120px; margin-top:5px\">\n",
       "\t    \t\t<img style=\"width:250px; height: auto; max-height:150px\" src=\"../../data/retrotech/images/885909457595.jpg\">\n",
       "\t    \t</div>\n",
       "\t    \t<div style=\"position:relative; float:left; clear:none; width: 80%; height:auto\">\n",
       "\t    \t\t<p style=\"font-size:24px; padding-left: 50px;\"><strong>\t\tName:</strong> Apple&#xAE; - iPad&#xAE; 2 with Wi-Fi - 32GB - Black\n",
       "\t\t\t\t\t<br><strong>\t\tManufacturer:</strong> Apple&#xAE;</p>\n",
       "\t    \t\t</p>\n",
       "\t    \t</div>\n",
       "    \t</div>\n",
       "    \t\n",
       "\t\t<div style=\"position:relative; clear:both; content: ' '; display: block; height: 1px; margin-top: 10px; margin-bottom:20px\">\n",
       "\t\t\t<hr style=\"color: gray; width: 95%;\" />\n",
       "\t\t</div>\n",
       "\t\t\n",
       "    \t<div style=\"position: relative; width: 100%; height:auto; overflow: auto;\">\n",
       "\t    \t<div style=\"position: relative; float:left; width: 120px; margin-top:5px\">\n",
       "\t    \t\t<img style=\"width:250px; height: auto; max-height:150px\" src=\"../../data/retrotech/images/885370315080.jpg\">\n",
       "\t    \t</div>\n",
       "\t    \t<div style=\"position:relative; float:left; clear:none; width: 80%; height:auto\">\n",
       "\t    \t\t<p style=\"font-size:24px; padding-left: 50px;\"><strong>\t\tName:</strong> Microsoft - Xbox 360 250GB Console\n",
       "\t\t\t\t\t<br><strong>\t\tManufacturer:</strong> Microsoft</p>\n",
       "\t    \t\t</p>\n",
       "\t    \t</div>\n",
       "    \t</div>\n",
       "    \t\n",
       "\t\t<div style=\"position:relative; clear:both; content: ' '; display: block; height: 1px; margin-top: 10px; margin-bottom:20px\">\n",
       "\t\t\t<hr style=\"color: gray; width: 95%;\" />\n",
       "\t\t</div>\n",
       "\t\t"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "user = \"u478462\"\n",
    "boosts = get_query_time_boosts(user, recs_collection)\n",
    "response = search_for_products(\"\", boosts)\n",
    "\n",
    "print(f\"Boost Query:\\n{boosts}\")\n",
    "display_product_search(\"\", response[\"docs\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1a12c0c5",
   "metadata": {},
   "source": [
    "## Listing 9.10"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "f61f8182",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Non-personalized Query\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div id=\"demo\">\n",
       "\t<center><input style=\"width:40%\" readonly type=\"text\" name=\"q\" value=\"tablet\">\n",
       "\t<input readonly type=\"submit\" value=\"Search\">\n",
       "\t</center>\n",
       "    <div class=\"results\">\n",
       "    \t\n",
       "\n",
       "    </div>\n",
       "</div>\n",
       "    \t<div style=\"position: relative; width: 100%; height:auto; overflow: auto;\">\n",
       "\t    \t<div style=\"position: relative; float:left; width: 120px; margin-top:5px\">\n",
       "\t    \t\t<img style=\"width:250px; height: auto; max-height:150px\" src=\"../../data/retrotech/images/5024545249224.jpg\">\n",
       "\t    \t</div>\n",
       "\t    \t<div style=\"position:relative; float:left; clear:none; width: 80%; height:auto\">\n",
       "\t    \t\t<p style=\"font-size:24px; padding-left: 50px;\"><strong>\t\tName:</strong> Memorial Tablet - CD\n",
       "\t\t\t\t\t<br><strong>\t\tManufacturer:</strong> Ltm/cd41</p>\n",
       "\t    \t\t</p>\n",
       "\t    \t</div>\n",
       "    \t</div>\n",
       "    \t\n",
       "\t\t<div style=\"position:relative; clear:both; content: ' '; display: block; height: 1px; margin-top: 10px; margin-bottom:20px\">\n",
       "\t\t\t<hr style=\"color: gray; width: 95%;\" />\n",
       "\t\t</div>\n",
       "\t\t\n",
       "    \t<div style=\"position: relative; width: 100%; height:auto; overflow: auto;\">\n",
       "\t    \t<div style=\"position: relative; float:left; width: 120px; margin-top:5px\">\n",
       "\t    \t\t<img style=\"width:250px; height: auto; max-height:150px\" src=\"../../data/retrotech/images/793447512228.jpg\">\n",
       "\t    \t</div>\n",
       "\t    \t<div style=\"position:relative; float:left; clear:none; width: 80%; height:auto\">\n",
       "\t    \t\t<p style=\"font-size:24px; padding-left: 50px;\"><strong>\t\tName:</strong> Stone Tablet - CD\n",
       "\t\t\t\t\t<br><strong>\t\tManufacturer:</strong> Important Records</p>\n",
       "\t    \t\t</p>\n",
       "\t    \t</div>\n",
       "    \t</div>\n",
       "    \t\n",
       "\t\t<div style=\"position:relative; clear:both; content: ' '; display: block; height: 1px; margin-top: 10px; margin-bottom:20px\">\n",
       "\t\t\t<hr style=\"color: gray; width: 95%;\" />\n",
       "\t\t</div>\n",
       "\t\t\n",
       "    \t<div style=\"position: relative; width: 100%; height:auto; overflow: auto;\">\n",
       "\t    \t<div style=\"position: relative; float:left; width: 120px; margin-top:5px\">\n",
       "\t    \t\t<img style=\"width:250px; height: auto; max-height:150px\" src=\"../../data/retrotech/images/600603138423.jpg\">\n",
       "\t    \t</div>\n",
       "\t    \t<div style=\"position:relative; float:left; clear:none; width: 80%; height:auto\">\n",
       "\t    \t\t<p style=\"font-size:24px; padding-left: 50px;\"><strong>\t\tName:</strong> Init&#x2122; - Tablet Sleeve - Olive\n",
       "\t\t\t\t\t<br><strong>\t\tManufacturer:</strong> Init&#x99;</p>\n",
       "\t    \t\t</p>\n",
       "\t    \t</div>\n",
       "    \t</div>\n",
       "    \t\n",
       "\t\t<div style=\"position:relative; clear:both; content: ' '; display: block; height: 1px; margin-top: 10px; margin-bottom:20px\">\n",
       "\t\t\t<hr style=\"color: gray; width: 95%;\" />\n",
       "\t\t</div>\n",
       "\t\t\n",
       "    \t<div style=\"position: relative; width: 100%; height:auto; overflow: auto;\">\n",
       "\t    \t<div style=\"position: relative; float:left; width: 120px; margin-top:5px\">\n",
       "\t    \t\t<img style=\"width:250px; height: auto; max-height:150px\" src=\"../../data/retrotech/images/27242831599.jpg\">\n",
       "\t    \t</div>\n",
       "\t    \t<div style=\"position:relative; float:left; clear:none; width: 80%; height:auto\">\n",
       "\t    \t\t<p style=\"font-size:24px; padding-left: 50px;\"><strong>\t\tName:</strong> Sony - AC Power Adapter for Sony Tablet S\n",
       "\t\t\t\t\t<br><strong>\t\tManufacturer:</strong> Sony</p>\n",
       "\t    \t\t</p>\n",
       "\t    \t</div>\n",
       "    \t</div>\n",
       "    \t\n",
       "\t\t<div style=\"position:relative; clear:both; content: ' '; display: block; height: 1px; margin-top: 10px; margin-bottom:20px\">\n",
       "\t\t\t<hr style=\"color: gray; width: 95%;\" />\n",
       "\t\t</div>\n",
       "\t\t\n",
       "    \t<div style=\"position: relative; width: 100%; height:auto; overflow: auto;\">\n",
       "\t    \t<div style=\"position: relative; float:left; width: 120px; margin-top:5px\">\n",
       "\t    \t\t<img style=\"width:250px; height: auto; max-height:150px\" src=\"../../data/retrotech/images/843163089211.jpg\">\n",
       "\t    \t</div>\n",
       "\t    \t<div style=\"position:relative; float:left; clear:none; width: 80%; height:auto\">\n",
       "\t    \t\t<p style=\"font-size:24px; padding-left: 50px;\"><strong>\t\tName:</strong> BlackBerry - Rapid Charger for BlackBerry PlayBook\n",
       "\t\t\t\t\t<br><strong>\t\tManufacturer:</strong> BlackBerry</p>\n",
       "\t    \t\t</p>\n",
       "\t    \t</div>\n",
       "    \t</div>\n",
       "    \t\n",
       "\t\t<div style=\"position:relative; clear:both; content: ' '; display: block; height: 1px; margin-top: 10px; margin-bottom:20px\">\n",
       "\t\t\t<hr style=\"color: gray; width: 95%;\" />\n",
       "\t\t</div>\n",
       "\t\t"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "query = \"tablet\"\n",
    "response = search_for_products(query, None)\n",
    "print(f\"Non-personalized Query\")\n",
    "display_product_search(query, response[\"docs\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "0ede50af",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Personalized Query\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div id=\"demo\">\n",
       "\t<center><input style=\"width:40%\" readonly type=\"text\" name=\"q\" value=\"tablet\">\n",
       "\t<input readonly type=\"submit\" value=\"Search\">\n",
       "\t</center>\n",
       "    <div class=\"results\">\n",
       "    \t\n",
       "\n",
       "    </div>\n",
       "</div>\n",
       "    \t<div style=\"position: relative; width: 100%; height:auto; overflow: auto;\">\n",
       "\t    \t<div style=\"position: relative; float:left; width: 120px; margin-top:5px\">\n",
       "\t    \t\t<img style=\"width:250px; height: auto; max-height:150px\" src=\"../../data/retrotech/images/885909457588.jpg\">\n",
       "\t    \t</div>\n",
       "\t    \t<div style=\"position:relative; float:left; clear:none; width: 80%; height:auto\">\n",
       "\t    \t\t<p style=\"font-size:24px; padding-left: 50px;\"><strong>\t\tName:</strong> Apple&#xAE; - iPad&#xAE; 2 with Wi-Fi - 16GB - Black\n",
       "\t\t\t\t\t<br><strong>\t\tManufacturer:</strong> Apple&#xAE;</p>\n",
       "\t    \t\t</p>\n",
       "\t    \t</div>\n",
       "    \t</div>\n",
       "    \t\n",
       "\t\t<div style=\"position:relative; clear:both; content: ' '; display: block; height: 1px; margin-top: 10px; margin-bottom:20px\">\n",
       "\t\t\t<hr style=\"color: gray; width: 95%;\" />\n",
       "\t\t</div>\n",
       "\t\t\n",
       "    \t<div style=\"position: relative; width: 100%; height:auto; overflow: auto;\">\n",
       "\t    \t<div style=\"position: relative; float:left; width: 120px; margin-top:5px\">\n",
       "\t    \t\t<img style=\"width:250px; height: auto; max-height:150px\" src=\"../../data/retrotech/images/635753493559.jpg\">\n",
       "\t    \t</div>\n",
       "\t    \t<div style=\"position:relative; float:left; clear:none; width: 80%; height:auto\">\n",
       "\t    \t\t<p style=\"font-size:24px; padding-left: 50px;\"><strong>\t\tName:</strong> Samsung - Galaxy Tab 10.1 - 16GB - Metallic Gray\n",
       "\t\t\t\t\t<br><strong>\t\tManufacturer:</strong> Samsung</p>\n",
       "\t    \t\t</p>\n",
       "\t    \t</div>\n",
       "    \t</div>\n",
       "    \t\n",
       "\t\t<div style=\"position:relative; clear:both; content: ' '; display: block; height: 1px; margin-top: 10px; margin-bottom:20px\">\n",
       "\t\t\t<hr style=\"color: gray; width: 95%;\" />\n",
       "\t\t</div>\n",
       "\t\t\n",
       "    \t<div style=\"position: relative; width: 100%; height:auto; overflow: auto;\">\n",
       "\t    \t<div style=\"position: relative; float:left; width: 120px; margin-top:5px\">\n",
       "\t    \t\t<img style=\"width:250px; height: auto; max-height:150px\" src=\"../../data/retrotech/images/635753493573.jpg\">\n",
       "\t    \t</div>\n",
       "\t    \t<div style=\"position:relative; float:left; clear:none; width: 80%; height:auto\">\n",
       "\t    \t\t<p style=\"font-size:24px; padding-left: 50px;\"><strong>\t\tName:</strong> Samsung - Galaxy Tab 10.1  - 32GB - Metallic Gray\n",
       "\t\t\t\t\t<br><strong>\t\tManufacturer:</strong> Samsung</p>\n",
       "\t    \t\t</p>\n",
       "\t    \t</div>\n",
       "    \t</div>\n",
       "    \t\n",
       "\t\t<div style=\"position:relative; clear:both; content: ' '; display: block; height: 1px; margin-top: 10px; margin-bottom:20px\">\n",
       "\t\t\t<hr style=\"color: gray; width: 95%;\" />\n",
       "\t\t</div>\n",
       "\t\t\n",
       "    \t<div style=\"position: relative; width: 100%; height:auto; overflow: auto;\">\n",
       "\t    \t<div style=\"position: relative; float:left; width: 120px; margin-top:5px\">\n",
       "\t    \t\t<img style=\"width:250px; height: auto; max-height:150px\" src=\"../../data/retrotech/images/885909457595.jpg\">\n",
       "\t    \t</div>\n",
       "\t    \t<div style=\"position:relative; float:left; clear:none; width: 80%; height:auto\">\n",
       "\t    \t\t<p style=\"font-size:24px; padding-left: 50px;\"><strong>\t\tName:</strong> Apple&#xAE; - iPad&#xAE; 2 with Wi-Fi - 32GB - Black\n",
       "\t\t\t\t\t<br><strong>\t\tManufacturer:</strong> Apple&#xAE;</p>\n",
       "\t    \t\t</p>\n",
       "\t    \t</div>\n",
       "    \t</div>\n",
       "    \t\n",
       "\t\t<div style=\"position:relative; clear:both; content: ' '; display: block; height: 1px; margin-top: 10px; margin-bottom:20px\">\n",
       "\t\t\t<hr style=\"color: gray; width: 95%;\" />\n",
       "\t\t</div>\n",
       "\t\t\n",
       "    \t<div style=\"position: relative; width: 100%; height:auto; overflow: auto;\">\n",
       "\t    \t<div style=\"position: relative; float:left; width: 120px; margin-top:5px\">\n",
       "\t    \t\t<img style=\"width:250px; height: auto; max-height:150px\" src=\"../../data/retrotech/images/5024545249224.jpg\">\n",
       "\t    \t</div>\n",
       "\t    \t<div style=\"position:relative; float:left; clear:none; width: 80%; height:auto\">\n",
       "\t    \t\t<p style=\"font-size:24px; padding-left: 50px;\"><strong>\t\tName:</strong> Memorial Tablet - CD\n",
       "\t\t\t\t\t<br><strong>\t\tManufacturer:</strong> Ltm/cd41</p>\n",
       "\t    \t\t</p>\n",
       "\t    \t</div>\n",
       "    \t</div>\n",
       "    \t\n",
       "\t\t<div style=\"position:relative; clear:both; content: ' '; display: block; height: 1px; margin-top: 10px; margin-bottom:20px\">\n",
       "\t\t\t<hr style=\"color: gray; width: 95%;\" />\n",
       "\t\t</div>\n",
       "\t\t"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "response = search_for_products(query, boosts)\n",
    "print(f\"Personalized Query\")\n",
    "display_product_search(query, response[\"docs\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "af0fca6f",
   "metadata": {},
   "source": [
    "Up next: [Vector-based Peronsalization](2.embedding-based-personalization.ipynb)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
